package com.strato.mvc.security.v1_0_0.interceptor;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.strato.annotation.osgi.v1_0_0.service.OsgiService;
import com.strato.annotation.osgi.v1_0_0.service.OsgiWired;
import com.strato.base.env.v1_0_0.GlobalEnvironment;
import com.strato.mvc.annotation.v1_0_0.invoker.MethodHttpInvoker;
import com.strato.mvc.api.v1_0_0.control.HttpInvoker;
import com.strato.mvc.api.v1_0_0.control.HttpInvokerInterceptor;
import com.strato.mvc.api.v1_0_0.control.PathVariableCollector;
import com.strato.mvc.api.v1_0_0.model.ModelAndView;
import com.strato.mvc.api.v1_0_0.user.Principal;
import com.strato.mvc.api.v1_0_0.user.UserContext;
import com.strato.mvc.api.v1_0_0.util.RequestMeta;
import com.strato.mvc.security.v1_0_0.annotation.SecurityConstraint;
import com.strato.mvc.security.v1_0_0.api.AuthenticationService;
import com.strato.mvc.security.v1_0_0.api.AuthorityService;

@OsgiService
public class SecurityConstraintInterceptor implements HttpInvokerInterceptor {

	private static final int ORDER = 110;

	public static final int NOT_LOGGED_IN_RESPONSE_STATUS=567;
	public static final String AJAX_HEADER="_ajax_";
	
	@OsgiWired
	private AuthenticationService authenticationService;
	
	@OsgiWired
	private AuthorityService authorityService;
	
	@Override
	public boolean canHandle(HttpServletRequest request, HttpServletResponse response, PathVariableCollector pvc, RequestMeta meta, HttpInvoker invoker) {
		if(!(invoker instanceof MethodHttpInvoker)){
			return false;
		}
		MethodHttpInvoker mi=(MethodHttpInvoker) invoker;
		Method method = mi.getMethod();
		if(method==null){
			return false;
		}
		SecurityConstraint sc = method.getAnnotation(SecurityConstraint.class);
		if(sc==null){
			return false;
		}
		return true;
	}

	@Override
	public boolean beforeInvocation(HttpServletRequest request, HttpServletResponse response, PathVariableCollector pvc, ModelAndView mav,HttpInvoker invoker) {
		MethodHttpInvoker mi=(MethodHttpInvoker) invoker;
		Method method = mi.getMethod();
		SecurityConstraint sc = method.getAnnotation(SecurityConstraint.class);
		String opers = sc.value();
		opers=GlobalEnvironment.getInstance().resolveString(opers);
		if(opers==null||opers.length()==0){
			return true;
		}
		Principal principal=(Principal) request.getSession().getAttribute(Principal.ATTR_PRINCIPAL_IN_SESSION);
		Object user=request.getSession().getAttribute(Principal.ATTR_USER_IN_SESSION);
		if(principal==null||principal.getUserId()==null){
			String ticket=authenticationService.extractTicket(request);
			if(ticket!=null){
				principal=authenticationService.validate(ticket);
				if(principal!=null){
					request.getSession().setAttribute(Principal.ATTR_PRINCIPAL_IN_SESSION, principal);
					user=authenticationService.extractUser(principal);
					principal.setUser(user);
					request.getSession().setAttribute(Principal.ATTR_USER_IN_SESSION, user);
					return checkOpers(principal,opers,request,response,mav);
				}
				
			}
			authenticationService.onUnauthenticated(request,response);
			return false;
		}
		return checkOpers(principal,opers,request,response,mav);
	}

	private boolean checkOpers(Principal principal, String opers, HttpServletRequest request, HttpServletResponse response, ModelAndView mav) {
		String[] operations=opers.split(",|;");
		boolean hasAuth=authorityService.check(principal,operations);
		if(!hasAuth){
			authorityService.onUnauthorized(request,response,mav);
			return false;
		}
		return true;
	}

	@Override
	public void invocationSuccess(HttpServletRequest request, HttpServletResponse response, PathVariableCollector pvc, ModelAndView mav, HttpInvoker invoker) {
	}

	@Override
	public void invokeFinally(HttpServletRequest request, HttpServletResponse response, PathVariableCollector pvc, HttpInvoker invoker) {
		UserContext.set(null);
		UserContext.setUser(null);
	}

	@Override
	public void invocationFailed(HttpServletRequest request, HttpServletResponse response, PathVariableCollector pvc, Exception e, HttpInvoker invoker) {
	}

	@Override
	public int getOrder() {
		return ORDER;
	}
}
